#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <string>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include "threadpool.hpp"
#include <functional>
#include "Task.hpp"

using namespace std;
string ip = "0.0.0.0";
int backlog = 5;
#define SIZE 1024

//线程池版本
class Server
{
public:
	// 构造函数
	Server(uint16_t port)
		: _port(port), _ip(ip), _listensocket(-1)
	{
	}

	// 初始化
	void ServerInit()
	{
		//_listeansocket是用来监听，不是用来通信的端口号
		_listensocket = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字
		cout << "socket success" << endl;

		struct sockaddr_in peer;
		peer.sin_family = AF_INET;					   // 表示使用ipv4
		peer.sin_port = htons(_port);				   // 将端口号网络字节序
		peer.sin_addr.s_addr = inet_addr(_ip.c_str()); // 传入IP地址

		int n = bind(_listensocket, (const struct sockaddr *)&peer, sizeof(peer)); // 绑定1p
		if (n < 0)
		{
			cout << "bind flase" << endl;
			exit(1);
		}
		cout << "bind success" << endl;

		// listen函数使用主动连接套接字变为被连接套接口
		// ，使得一个进程可以接受其它进程的请求，从而成为一个服务器进程。
		// 在TCP服务器编程中listen函数把进程变为一个服务器，并指定相应的套接字变为被动连接。
		n = listen(_listensocket, backlog);
		if (n < 0)
		{
			cout << "listen false" << endl;
			exit(2);
		}
		cout << "listen success" << endl;
	}

	~Server()
	{
	}

	// 启动服务端进程——线程池
	void ServerStart4()
	{
		Threadpool<ThreadData> td(10);
		td.Create();
		struct sockaddr_in addr; // 存储客户端的信息
		socklen_t len = sizeof(addr);

		// 如果没有客户端连接服务端，则accept会阻塞等待新连接
		// 如果有客户端需要连接服务端，则返回一个用于网络通信的描述符sock
		int sock = accept(_listensocket, (struct sockaddr *)&addr, &len);

		if (sock < 0)
		{
			cout << "accept false" << endl;
			exit(3);
		}
		cout << "accept success" << endl;

        
		ThreadData t(sock);
		td.push(t);
	}

private:
	uint16_t _port;	   // 端口号
	string _ip;		   // ip地址
	int _listensocket; // socket()返回值
};



/*
class Server;
class ThreadData
{
public:
	ThreadData(int fd, Server* tsvr) : sockfd(fd), _tsvr(tsvr)
	{
	}

public:
	int sockfd;
	Server *_tsvr;
};

class Server
{
public:
	// 构造函数
	Server(uint16_t port)
		: _port(port), _ip(ip), _listensocket(-1)
	{
	}

	// 初始化
	void ServerInit()
	{
		//_listeansocket是用来监听，不是用来通信的端口号
		_listensocket = socket(AF_INET, SOCK_STREAM, 0); // 创建套接字
		cout << "socket success" << endl;

		struct sockaddr_in peer;
		peer.sin_family = AF_INET;					   // 表示使用ipv4
		peer.sin_port = htons(_port);				   // 将端口号网络字节序
		peer.sin_addr.s_addr = inet_addr(_ip.c_str()); // 传入IP地址

		int n = bind(_listensocket, (const struct sockaddr *)&peer, sizeof(peer)); // 绑定1p
		if (n < 0)
		{
			cout << "bind flase" << endl;
			exit(1);
		}
		cout << "bind success" << endl;

		// listen函数使用主动连接套接字变为被连接套接口
		// ，使得一个进程可以接受其它进程的请求，从而成为一个服务器进程。
		// 在TCP服务器编程中listen函数把进程变为一个服务器，并指定相应的套接字变为被动连接。
		n = listen(_listensocket, backlog);
		if (n < 0)
		{
			cout << "listen false" << endl;
			exit(2);
		}
		cout << "listen success" << endl;
	}

	// 处理方式
	void hander(int sock)
	{
		char buffer[SIZE]; // 定义缓冲区，用于存放客户端发来的数据
		while (true)
		{
			size_t n = read(sock, buffer, sizeof(buffer) - 1); // 减一是为了留出一个\0
			if (n > 0)
			{
				buffer[n] = '\0'; // 把发来的\n覆盖掉

				cout << "Server get a data: " << buffer << endl;
				string out;
				out += buffer;
				write(sock, out.c_str(), out.size()); // 将数据写回
			}
			else
			{
				cout << "Client quit" << endl;
				break;
			}
		}
	}

	// 启动服务端进程
	void ServerStart()
	{
		struct sockaddr_in addr; // 存储客户端的信息
		socklen_t len = sizeof(addr);

		// 如果没有客户端连接服务端，则accept会阻塞等待新连接
		// 如果有客户端需要连接服务端，则返回一个用于网络通信的描述符sock
		int sock = accept(_listensocket, (struct sockaddr *)&addr, &len);
		if (sock < 0)
		{
			cout << "accept false" << endl;
			exit(3);
		}
		cout << "accept success" << endl;

		// 不断的处理客户端发来的任务
		hander(sock);
		// 退出该函数时，客户端已经退出，需要将进行网络传输的文件描述符释放，否则会引起资源泄露
		close(sock);
		// 服务端释放通信的文件描述符，但不释放监听的文件描述符
		// 服务端进程可以继续使用该监听文件描述符阻塞等待下一个客户端连接
	}

	// 析构函数
	// 按道理不释放监听文件描述符也是一种资源泄漏，但是服务器进程大部分需要长期运行
	// 只有进程出问题了进程才会退出，而当进程退出时，它占用的资源也归还了操作系统，所以不释放也无所谓
	~Server()
	{
	}




	/*
	// 启动服务端进程——多进程版本
	void ServerStart1()
	{
		struct sockaddr_in addr; // 存储客户端的信息
		socklen_t len = sizeof(addr);

		// 如果没有客户端连接服务端，则accept会阻塞等待新连接
		// 如果有客户端需要连接服务端，则返回一个用于网络通信的描述符sock
		int sock = accept(_listensocket, (struct sockaddr *)&addr, &len);
		if (sock < 0)
		{
			cout << "accept false" << endl;
			exit(3);
		}
		cout << "accept success" << endl;

		pid_t id = fork();
		if (id == 0)
		{
			// 由于子进程也继承了父进程的监听套接字，而监听套接字只需要一个，所以需要关闭
			close(_listensocket);
			if (fork() > 0)
			{
				// 子进程再次创建子进程，fork返回孙子进程的pid
				exit(0); // 服务器的子进程退出，使孙子进程变成了孤儿进程
			}

			// 不断的处理客户端发来的任务
			hander(sock);
			// 退出该函数时，客户端已经退出，需要将进行网络传输的文件描述符释放，否则会引起资源泄露
			close(sock);
			//退出孙子进程，由于他是孤儿进程，所以会被操作系统自行回收
			exit(0);
		}
	}
	*/

/*
static void *Routine(void *args)
{
	pthread_detach(pthread_self());//将线程分离，执行完毕后操作系统自动回收
	ThreadData *td = static_cast<ThreadData *>(args);
	td->tsvr->hander(td->sockfd);
	delete td;
	return nullptr;
}

// 启动服务端进程——多线程版本
void ServerStart3()
{
	struct sockaddr_in addr; // 存储客户端的信息
	socklen_t len = sizeof(addr);

	// 如果没有客户端连接服务端，则accept会阻塞等待新连接
	// 如果有客户端需要连接服务端，则返回一个用于网络通信的描述符sock
	int sock = accept(_listensocket, (struct sockaddr *)&addr, &len);
	if (sock < 0)
	{
		cout << "accept false" << endl;
		exit(3);
	}
	cout << "accept success" << endl;

	// 创建新线程
	pthread_t tid;
	ThreadData *p = new ThreadData(sock, this);
	pthread_create(&tid, nullptr, Routine, p);//创造线程并且执行
	sleep(20);//这里睡眠20s，防止线程结束太快，来不及调用其他函数和打印
}


private:
	uint16_t _port;	   // 端口号
	string _ip;		   // ip地址
	int _listensocket; // socket()返回值
};
*/